﻿using Avalonia.Threading;
using Bilibili.Common;
using Bilibili.Common.Log;
using Bilibili.Model.Common;
using Bilibili.WebClient;
using LibVLCSharp.Avalonia;
using LibVLCSharp.Shared;
using System;
using System.Diagnostics;
using System.IO;

namespace Avalonia.BiliBili.Libs.Medias
{
    public sealed class VlcPlayer
    {
        private bool IsLive { get; set; }
        private bool NewResource = true;
        private string RoomId { get; set; }
        public event CallbackNameObject Callback;
        public bool IsPlaying => MediaPlayer.IsPlaying;
        public static LibVLC LibVlc { get; private set; }
        private static MediaPlayer MediaPlayer { get; set; }
        private static readonly object objectObj = new object();
        static VlcPlayer()
        {
            LibVlc = new LibVLC();
            LibVlc.SetUserAgent("bilibili", Current.PLAY_USER_AGENT);
            if (Debugger.IsAttached)
                LibVlc.Log += LibVlc_Log;
            MediaPlayer = new MediaPlayer(LibVlc) { EnableHardwareDecoding = true };
        }
        private static void LibVlc_Log(object sender, LogEventArgs e)
        {
#if DEBUG
            if (Debugger.IsAttached)
                Debug.WriteLine(e.Message);
#endif
        }
        public VlcPlayer(VideoView videoView)
        {
            Dispatcher.UIThread.InvokeAsync(() =>
            {
                MediaPlayer.Stopped += MediaPlayer_Stopped;
                MediaPlayer.TimeChanged += MediaPlayer_TimeChanged;
                MediaPlayer.PositionChanged += MediaPlayer_PositionChanged;
                videoView.MediaPlayer = MediaPlayer;
            });
        }
        public void InitLive(string roomId)
        {
            IsLive = true;
            RoomId = roomId;
        }
        private void MediaPlayer_Stopped(object sender, EventArgs e)
        {
            lock (objectObj)
                Callback?.Invoke("stopped", sender);
        }
        private void MediaPlayer_TimeChanged(object sender, MediaPlayerTimeChangedEventArgs e)
        {
            lock (objectObj)
            {
                try
                {
                    if (NewResource)
                    {
                        Callback?.Invoke("duration", MediaPlayer.Length);
                        NewResource = false;
                    }
                }
                catch { }
            }
        }
        private void MediaPlayer_PositionChanged(object sender, MediaPlayerPositionChangedEventArgs e)
        {
            lock (objectObj)
            {
                try
                {
                    if (!NewResource)
                    {
                        var value = Convert.ToInt64(MediaPlayer.Length * e.Position);
                        Callback?.Invoke("position", value);
                    }
                }
                catch { }
            }
        }
        public void Play()
        {
            try
            {
                MediaPlayer.Play();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("Play", ex);
            }
        }
        public bool Play(string videoUrl, FileInfo file, DataSourceHeader sourceHeader, out string message)
        {
            try
            {
                NewResource = true;
                var mediaItem = new MediaItem(LibVlc, new Uri(videoUrl));
                if (IsLive)
                    mediaItem.SetHeader("https://live.bilibili.com/" + RoomId);
                else
                    mediaItem.SetHeader(sourceHeader);
                if (file != null)
                    mediaItem.AddSubtitle(file);
                MediaPlayer.Play(mediaItem);
                message = string.Empty;
                return true;
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("Play", ex);
                message = "播放失败：" + ex.Message;
                return false;
            }
        }
        public bool Play(string url, FileInfo file, out string msg) => Play(url, file, null, out msg);
        public bool Play(MediaItem mediaItem, DataSourceHeader sourceHeader, out string message)
        {
            try
            {
                NewResource = true;
                mediaItem.SetHeader(sourceHeader?.Referer ?? string.Empty);
                MediaPlayer.Play(mediaItem);
                message = string.Empty;
                return true;
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("Play", ex);
                message = "播放失败：" + ex.Message;
                return false;
            }
        }
        public void SeekTo(double position)
        {
            try
            {
                var ts = TimeSpan.FromMilliseconds(position);
                MediaPlayer.SeekTo(ts);
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("SeekTo", ex);
            }
        }
        public void Pause()
        {
            try
            {
                MediaPlayer.Pause();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("Pause", ex);
            }
        }
        public void Stop()
        {
            try
            {
                MediaPlayer.Stop();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("Pause", ex);
            }
        }
    }
}